package info.hexin.quartz.annotation;

import info.hexin.quartz.redis.RedisClient;
import info.hexin.quartz.spring.CronScheduledAnnoationBeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2016/1/29.
 */
@Component
public class ScheduleLock  implements ApplicationListener {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private static final String LOCK_KEY = "scheduler_key";
    private static final long LOCK_OUTTIME = 15 * 1000;
    private String owner = UUID.randomUUID().toString().replaceAll("-", "");

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);


    public volatile boolean haslock = false;
    public boolean startBad = false;


    @Autowired
    public RedisClient redisClient;

    @Autowired
    CronScheduledAnnoationBeanPostProcessor postProcessor;


    @PostConstruct
    public void initLock() {

    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        String lockobj = owner + "," + System.currentTimeMillis();
        haslock = redisClient.setNx(LOCK_KEY, lockobj);
        logger.info("当前写入redis状态>>>" + haslock);
        executor.scheduleAtFixedRate((Runnable) () -> {
            daemon();
        }, 0, 2, TimeUnit.SECONDS);
    }

    public void daemon() {
        String key = (String) redisClient.get(LOCK_KEY);
        logger.info("获得当前的key值为:" + key);
        if (!StringUtils.isEmpty(key)) {
            String[] keytimes = key.split(",");
            String currentkey = keytimes[0];
            long currentkeytime = Long.valueOf(keytimes[1]);
            logger.info("当前key不为空，检查是否自己持有的key");
            if (currentkey.equals(owner)) {
                if (!startBad) {
                    logger.info("是自己持有的key，更新时间戳");
                    redisClient.set(LOCK_KEY, owner + "," + System.currentTimeMillis());
                } else {
                    logger.info("是自己持有的key，启动失败，不更新时间戳");
                }
            } else {
                if (haslock) {
                    logger.info("之前启动启动调度，停止调度，自己释放锁");
                    postProcessor.reRegisterDestroy();
                    haslock = false;
                } else {
                    logger.info(" 不是自己持有的key，检查key是否过期");
                    long laterTime = System.currentTimeMillis() - currentkeytime;
                    if (laterTime > LOCK_OUTTIME) {
                        logger.info("当前key 已经过期，进行回收，尝试获取新的key，超时时间：" + laterTime);
                        String oldkey = (String) redisClient.getSet(LOCK_KEY, owner + "," + System.currentTimeMillis());
                        if (oldkey.equals(key)) {
                            logger.info("当前节点放入新的key，检查替换回来的key和之前的一致，获得key：置换前的key：" + oldkey);
                            haslock = true;
                            registerTask();
                        } else {
                            logger.info("当前节点放入新的key，检查替换回来的key和之前的不一致，key别的节点获得：当前的key：" + oldkey);
                        }
                    } else {
                        logger.info("当前锁没有过期，更新时间：{}秒前", (System.currentTimeMillis() - currentkeytime) / 1000);
                    }
                }
            }
        } else {
            if(haslock){
                logger.info("当前持有的key已经被删除，开始注册调度，并开始写入心跳：");
            } else {
                haslock = redisClient.setNx(LOCK_KEY, owner + "," + System.currentTimeMillis());
                if (haslock) {
                    logger.info("当前key已经被删除，当前节点获得到key，开始注册调度，并开始写入心跳：");
                    registerTask();
                }
            }
        }

    }

    void registerTask() {
        logger.info("scheduled 获得了锁，开始注册服务");
        postProcessor.reRegisterDestroy();
        logger.info("scheduled 注册服务个数>>"+postProcessor.objectmap.size());
        for (Object o : postProcessor.objectmap.values()) {
            postProcessor.getObject(o, o.getClass().getName());
        }
        postProcessor.reRegister();
    }
}
